#!/bin/bash -e
#
#   Neutron3529's Unity Game Plugin
#   Copyright (C) 2022 Neutron3529
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as
#   published by the Free Software Foundation, either version 3 of the
#   License, or (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
############################################################################
#
#   * compile instructions: put this file and `utils.cs` in `steamapps`
#   * folder, open a terminal in the same folder, and execute:
#   *
#   * ```
#   *     chmod +x ${file}.cs
#   *     ./${file}.cs
#   * ```
#   *
#   * then the mod will be compiled automatically.
#   *
#   * Here we wrote a shebang like file, which is correct
#   * in my computer (Manjaro XFCE), if such script do not work
#   * in your computer, you could just try the instructions below :

export GAME_NAME="${0%\.cs}"                                # might modify if the name mismatch.
export GAME_DIR="$GAME_NAME"                                # might be modified, but "$GAME_NAME" cover most of the cases.

export FILE_NAME="$0"
export ASSEMBLY="Assembly-CSharp"                           # might be modified
export UTILS="utils.cs"                                     # might be modified if you do not put utils.cs in the current dir.
export PLUGIN_ID="Neutron3529.Cheat"                        # should be modified
export NAMESPACE_ID="Neutron3529.Cheat"                     # should be modified
export GAME_BASE_DIR="common/$GAME_DIR"                     # should modify GAME_DIR instead since GAME_DIR == GAME_NAME is almost always true.

export IFS=$'\n' # to disable the annoying space.
export DOTNET="dotnet" # the location of the DOTNET executable file.
[ -z "$DOTNET_CSC_DLL" ] && export DOTNET_CSC_DLL=`\ls /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll` # In manjaro, the csc.dll is located in /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll

__MODE_VERBOSE=99 # is the line number of "#define VERBOSE", may be modified
__MODE_DEBUG__=$((__MODE_VERBOSE+1))
__MODE_RELEASE=$((__MODE_DEBUG__+1))

case $1 in
    V)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    v)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    VERBOSE) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    verbose) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    D)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    d)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    DEBUG)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    debug)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    *)       _MODE__SELECT_=$__MODE_RELEASE     ;;
esac

( yes "" | head -n $_MODE__SELECT_ | head -n-1  ; tail $FILE_NAME -n+$_MODE__SELECT_ ) | sed s/%%NAMESPACE_ID%%/${NAMESPACE_ID}/g | sed s/%%PLUGIN_ID%%/${PLUGIN_ID}/g | $DOTNET $DOTNET_CSC_DLL -nologo -t:library \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/0Harmony.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.Harmony.dll" \
  `[ -e "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll" ] && echo "-r:\"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll\""` \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.Core.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.AIModule.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.CoreModule.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.UI.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/mscorlib.dll" \
  $(for i in "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/$ASSEMBLY"*.dll ; do echo -e "-r:\"$i\"\n" ; done) \
  -out:"${GAME_BASE_DIR}/BepInEx/plugins/${FILE_NAME%.*}".dll \
  -optimize `[ "$_MODE__SELECT_" == "$__MODE_DEBUG__" ] && echo -debug` \
  $UTILS - && rm -f "${GAME_BASE_DIR}/BepInEx/config/${PLUGIN_ID}.cfg";

if [ -n "$2" ]; then
    git add ${FILE_NAME}
    case $2 in
        R) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        r) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        RANDOM) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        random) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        U) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        u) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        UPLOAD) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        upload) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        *) git commit -am "$2" ;;
    esac
    git push
fi
exit

#define VERBOSE // the line of __MODE_VERBOSE
#define DEBUG



using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;

using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

namespace %%NAMESPACE_ID%%
{
    [BepInPlugin("%%PLUGIN_ID%%", "%%NAMESPACE_ID%%", "0.1.0")]
    public class Cheat : BaseUnityPlugin {
        public static float statmul=10f;
        public static int four=9000;
        void Start() {
            var harmony=new Harmony("%%PLUGIN_ID%%");
            Logger.LogInfo("此Mod使用AGPL-v3许可发布，如果你使用了这里的代码，请按照相同许可发布你修改后的mod。");
#if DEBUG
            logger=Logger.LogInfo;
            logger=delegate(string s){Logger.LogInfo("%%NAMESPACE_ID%%:"+s);};
            logger("开始注入");
#endif
            if((statmul=Config.Bind("config", "OfficerManagerCreateOfficerModel", statmul, "文职史诗级加强").Value)>=1f){
                harmony.PatchAll(typeof(OfficerManagerCreateOfficerModel));
                harmony.PatchAll(typeof(WeaponModelGetOfficerWeapon));
                harmony.PatchAll(typeof(OfficerModeldefense));
                logger("文职史诗级加强-注入完成");
            }
            if((four=Config.Bind("config", "WorkerPrimaryStatGetAddedStat", four, "升级时将员工四维改为此数值").Value)>0){
                harmony.PatchAll(typeof(WorkerPrimaryStatGetAddedStat));
                logger("升级时将员工四维改为此数值-注入完成");
            }
            if(Config.Bind("config", "UseSkillCalculateDmgExp", true, "员工经验增加").Value){
                harmony.PatchAll(typeof(UseSkillCalculateDmgExp));
                logger("员工经验增加-注入完成");
            }
            if(Config.Bind("config", "CreatureSelectUIOnClickReExtract", true, "异想体无限刷新").Value){
                harmony.PatchAll(typeof(CreatureSelectUIOnClickReExtract));
                logger("异想体无限刷新-注入完成");
            }
            if(Config.Bind("config", "CreatureEquipmentMakeInfoGetProb", true, "以概率1获取EGO饰品，且未锁定饰品在进入房间时会自动更改成较优版本").Value){
                harmony.PatchAll(typeof(AgentModelOnEnterRoom));
                harmony.PatchAll(typeof(CreatureEquipmentMakeInfoGetProb));
                logger("以概率1获取EGO饰品，且未锁定饰品在进入房间时会自动更改成较优版本-注入完成");
            }
            if(Config.Bind("config", "CreatureModelGetRedusedWorkProbByCounter.CreatureModelProbReductionValue.UseSkillProgressWork", true, "工作成功率与工作量大幅增加").Value){
                harmony.PatchAll(typeof(CreatureModelGetRedusedWorkProbByCounter));
                harmony.PatchAll(typeof(CreatureModelProbReductionValue));
                harmony.PatchAll(typeof(UseSkillProgressWork));
                logger("工作成功率与工作量大幅增加-注入完成");
            }
            if(Config.Bind("config", "IronMaidenPermitCancelCurrentWork.IronMaiden_damage.IronMaidenOnReleaseWork.IronMaidenOnStageEnd", true, "我们必将改变一切-允许停止工作，且伤害降低").Value){
                harmony.PatchAll(typeof(IronMaidenPermitCancelCurrentWork));
                harmony.PatchAll(typeof(IronMaiden_damage));
                harmony.PatchAll(typeof(IronMaidenOnReleaseWork));
                harmony.PatchAll(typeof(IronMaidenOnStageEnd));
                logger("我们必将改变一切-允许停止工作，且伤害降低-注入完成");
            }

            logger("叮~修改器启动，请安心游戏");
        }
        [HarmonyPatch(typeof(OfficerManager), "CreateOfficerModel")]
        class OfficerManagerCreateOfficerModel {
            static void Postfix(OfficerModel __result) {
                __result.baseMaxHp=(int)((float)__result.baseMaxHp*statmul);
                __result.baseMaxMental=(int)((float)__result.baseMaxMental*statmul);
                __result.baseMovement*=statmul;
                __result.hp=(float)__result.maxHp;
                __result.mental=(float)__result.baseMaxMental;
            }
        }
        [HarmonyPatch(typeof(WeaponModel), "GetOfficerWeapon")]
        class WeaponModelGetOfficerWeapon {
            static IEnumerable<CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable<CodeInstruction> instructions) {
                logger("%%PLUGIN_ID%%-正在注入类别"+__originalMethod.DeclaringType.Name+"的"+__originalMethod.Name+"方法");
                instructions = new CodeMatcher(instructions)
                    .MatchForward(true, // false = move at the start of the match, true = move at the end of the match
                        new CodeMatch(OpCodes.Ldc_I4_2)
                    ).Repeat( matcher => // Do the following for each match
                        matcher
                        .SetAndAdvance(
                            OpCodes.Ldc_I4,200064//200038
                        )
                    ).InstructionEnumeration();
                return instructions;
            }
        }
        [HarmonyPatch(typeof(OfficerModel), "defense",MethodType.Getter)]
        class OfficerModeldefense {
            static bool Prefix(ref DefenseInfo __result) {
                __result=DefenseInfo.zero;
                __result.R=__result.W=__result.B=__result.P=-1f;
                return false;
            }
        }
        [HarmonyPatch(typeof(WorkerPrimaryStat), "GetAddedStat")]
        class WorkerPrimaryStatGetAddedStat {
            static void Postfix(WorkerPrimaryStat __result) {
                __result.hp=four;
                __result.mental=four;
                __result.work=four;
                __result.battle=four;
            }
        }
        [HarmonyPatch(typeof(UseSkill), "CalculateDmgExp")]
        class UseSkillCalculateDmgExp {
            static void Postfix(ref float __result) {
                __result=10f;
            }
        }
        [HarmonyPatch(typeof(CreatureSelectUI), "OnClickReExtract")]
        class CreatureSelectUIOnClickReExtract {
            static void Postfix(CreatureSelectUI __instance, ref bool ____reExtracted) {
                ____reExtracted=false;
                __instance.reExtractController.Show();
            }
        }
        [HarmonyPatch(typeof(CreatureEquipmentMakeInfo), "GetProb")]
        class CreatureEquipmentMakeInfoGetProb {
            static void Postfix(ref float __result) {
                __result=1f;
            }
        }
        [HarmonyPatch(typeof(CreatureModel), "GetRedusedWorkProbByCounter")]
        class CreatureModelGetRedusedWorkProbByCounter {
            static void Postfix(ref int __result) {
                __result=-100;
            }
        }
        [HarmonyPatch(typeof(CreatureModel), "ProbReductionValue",MethodType.Getter)]
        class CreatureModelProbReductionValue {
            static void Postfix(ref int __result) {
                __result=-100;
            }
        }
        class UseSkillProgressWork {
            static IEnumerable<MethodBase> TargetMethods(){
                foreach(MethodInfo m in typeof(UseSkill).GetMethods((BindingFlags)(-1)))if(m.Name=="ProgressWork" || m.Name=="ProcessWorkNarration" || m.Name=="OnFixedUpdate" || m.Name=="GetMaxCubCount"){
                    logger("注入GetTraitEffect方法+1");
                    yield return m;
                }
            }
            static IEnumerable<CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable<CodeInstruction> instructions) {
                logger("%%PLUGIN_ID%%-正在注入类别"+__originalMethod.DeclaringType.Name+"的"+__originalMethod.Name+"方法");
                instructions = new CodeMatcher(instructions)
                    .MatchForward(false, // false = move at the start of the match, true = move at the end of the match
                        new CodeMatch(OpCodes.Ldfld,typeof(UseSkill).GetField("maxCubeCount"))
                    ).Repeat( matcher => // Do the following for each match
                        matcher
                        .Advance(1)
                        .InsertAndAdvance(
                            new CodeInstruction(OpCodes.Ldc_I4,10),
                            new CodeInstruction(OpCodes.Mul)
                        )
                        .Advance(1)
                    ).InstructionEnumeration();
#if VERBOSE
                int ii=0;
#endif
                foreach(var i in instructions){
#if VERBOSE
                    ii++;
                    logger(ii.ToString()+" : "+i.ToString());
#endif
                    yield return i;
                }
            }
        }
        [HarmonyPatch(typeof(AgentModel), "OnEnterRoom")]
        class AgentModelOnEnterRoom {
            static void Postfix(AgentModel __instance) {
                foreach(int i in new int[]{
                    4  ,// 头部   憎恶女王
                    5  ,// 脸颊   「一无所有」
                    15 ,// 左背   白夜
                    23 ,// 胸部   白雪公主的苹果
                    31 ,// 颈部   银河之子
                    32 ,// 口罩   小红帽雇佣兵
                    33 ,// 面部   又大又可能很坏的狼
                    35 ,// 眼部   审判鸟
                    38 ,// 右背   终末鸟
                    39 ,// 手部   贪婪女王
                    40 ,// 手套   小王子
                    103,// 口部   魔弹射手
                    104,// 头饰   阴
                })__instance.AttachEGOgift(EGOgiftModel.MakeGift(EquipmentTypeList.instance.GetData(400000+i)));
            }
        }
        [HarmonyPatch(typeof(IronMaiden), "PermitCancelCurrentWork")]
        class IronMaidenPermitCancelCurrentWork {
            static void Postfix(ref bool __result) {
                __result=true;
            }
        }
        [HarmonyPatch(typeof(IronMaiden), "_damage",MethodType.Getter)]
        class IronMaiden_damage {
            static void Postfix(ref float __result) {
                __result=0.01f;
            }
        }
        [HarmonyPatch(typeof(IronMaiden), "OnReleaseWork")]
        class IronMaidenOnReleaseWork {
            static void Postfix(ref AgentModel ___lockupAgent) {
                ___lockupAgent=null;
            }
        }
        [HarmonyPatch(typeof(IronMaiden), "OnStageEnd")]
        class IronMaidenOnStageEnd {
            static void Prefix(ref AgentModel ___lockupAgent) {
                ___lockupAgent=null;
            }
        }
#if DEBUG
        public static Action<string> logger;
#else
        public static void logger(string s){}
#endif
    }
}

